﻿/**************************************************************************************************
* @file SimulationTimer.h
* @note 仿真时钟实现
* @author g00034
* @data 2019-1-16
**************************************************************************************************/
#ifndef SIMULATIONT_TIMER_H
#define SIMULATIONT_TIMER_H
#ifdef WIN32
#include <windows.h>
#include <oleauto.h>
#else
#include <sys/time.h>
#endif
#include <QThread>
class CTimer : public QThread
{
	Q_OBJECT
public:
	CTimer()
		:m_dSec(1.0)
		,m_bRun(true)
		,m_bTimer(false)
	{
#ifdef WIN32
		QueryPerformanceFrequency(&m_sFreq);
		m_dQuadPartRec = 1.0/(double)m_sFreq.QuadPart;
#endif
		QThread::start();//QThread::HighestPriority
	}

	~CTimer()
	{
		m_bRun = false;
		m_bTimer = false;
		quit();
		//x00038 qt线程停止 调用quit()后需要调用wait()
		wait();
	}

	void start(int nMSec)
	{
		m_dSec = nMSec/1000.0;
		reset();
		m_bTimer = true;		
	}

	void stop()
	{
		m_bTimer = false;
	}

protected:
	void reset()
	{
#ifdef WIN32
		QueryPerformanceCounter(&m_sStart);
#elif linux
		gettimeofday(&tvStart,NULL);
#endif
	}

	virtual void run()
	{
		while(m_bRun)
		{
			if (m_bTimer)
			{
#ifdef WIN32
				LARGE_INTEGER t;
				QueryPerformanceCounter(&t);
				double dTime = (double)(t.QuadPart - m_sStart.QuadPart) * m_dQuadPartRec;
				if (dTime >= m_dSec)
#elif linux
				gettimeofday(&tvStop,NULL);
				double dTime = (double)(tvStop.tv_sec - tvStart.tv_sec) + (double)(tvStop.tv_usec - tvStart.tv_usec)/1000000000.0;
				if (dTime>= m_dSec)
#endif	
				{
					reset();
					emit timeoutSignal(dTime);	
				}
				//最小速度为0.001 降低cpu占用率
				msleep(1);
			}	
		}
	}
signals:
	void timeoutSignal(double dTime);

protected:
#ifdef WIN32
	LARGE_INTEGER m_sFreq;
	LARGE_INTEGER m_sStart;
#elif linux
	struct timeval tvStart;
	struct timeval tvStop;
#endif
	bool m_bRun;
	bool m_bTimer;
	double m_dSec;
	double m_dQuadPartRec;
};

class CFxSimulationTimer : public QObject
{
	Q_OBJECT
public:
	static CFxSimulationTimer* instance();

	static void unstance();

protected:
	CFxSimulationTimer();
	~CFxSimulationTimer();	

public:
	void setTimeBegin(double dTime) { m_dTimeBegin = dTime; }
	double getTimeBegin(){return m_dTimeBegin;}

	double getTimeCurrent() { return m_dTimeCurrent; }
	void setTimeCurrent(double dTime) { m_dTimeCurrent = dTime;}

	void setTimeCurrentFrame() { m_dTimeCurrentFrame = m_dTimeCurrent; }
	double getTimeCurrentFrame() {return m_dTimeCurrentFrame;}

	double getTimeRatio() { return m_dTimeRatio; }
	void setTimeRatio(double dRatio ) { m_dTimeRatio = dRatio; }

public:
	void start();
	void stop();
	void pause();
	bool isPause(){ return !m_bTick; }
	void reverse();
	void enableClockTimer(bool bTick);
	void tick(double dSec);

	private slots:
		void tickSlot(double dTime);

private:
	static CFxSimulationTimer* s_pSimulationTimer;
	bool m_bTick;              // 时钟是否在走
	double m_dTimeBegin;  // 起始的逻辑时间（天文）
	double m_dTimeCurrent;    // 当前的仿真时间 = m_dTickTime*m_dTimeRatio，但m_dTimeRatio是可调整的
	double m_dTimeCurrentFrame; // 记录的当前帧仿真时间
	double m_dTimeRatio;       // 仿真时间比  ΔD日时间/Δ时钟走过Tick的时间 或者说   仿真时间/Δ时钟走过Tick的时间
	double m_dDirection;       // 用绝对值为1.0的数代表时钟方向
	double m_dTimeTick;         // 计时器周期 单位：毫秒
	CTimer m_timerTick; // 计时器
};
double calToJD(int nYear, int nMonth, int nDay, int nHour, int nMin, double dSec);

void jdToCal(double dJD, int& nYear, int& nMonth, int& nDay,int& nHour, int& nMin, double& dSec);

#endif// SIMULATIONT_TIMER_H
